/*
 * Date         Author         Note
 * 2015.06.17   wzwz           纱嘴间距
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mh/common.h>
#include <mh/sram.h>
#include <mh/mac.h>
#include "knit.h"
#include <mh/mh_file.h>
#include "decript.h"
#include "prefixknit.h"
#include "backpiece.h"
#include "time.h"


/*
 *
 */
SYS_LOG* GetSysLogList(MH_KNIT *p)
{
    return &p->log_list;
}
/*
 *
 */
int ClearSysLog(MH_KNIT *p)
{
    SYS_LOG *next = p->log_list.next;
    p->log_list.total = 0;
    while(next)
    {
        p->log_list.next = next->next;
        free(next);
        next = p->log_list.next;
    }
    return remove(SYS_LOG_FILE);
}
/*
 *
 */
void AddSysLog(MH_KNIT *p, int type, int error)
{
    SYS_LOG *log = calloc(1, sizeof(SYS_LOG));
    log->type = type;
    log->code = error;
    log->time = time(NULL);
    log->next = p->log_list.next;
    p->log_list.next = log;
    ++p->log_list.total;
}
//int GetLogTotal(MH_KNIT *P)
/*
 *
 */
SYS_LOG* GetLogItem(SYS_LOG *header, uint index)
{
    int i = 0;
    SYS_LOG *q = NULL;
    q = header->next;
    while(i < index)
    {
        if(!q)
        {
            break;
        }
        q = q->next;
        ++i;
    }
    return q;
}
/*
 *
 */
int GetLogTypeList(SYS_LOG *out, const SYS_LOG *in, int type, int condition)
{
    int ret = 0;
    memset(out, 0,sizeof(SYS_LOG));
    SYS_LOG **next = &out->next;
    switch(type)
    {
    case LOG_TYPE_SAME_DAY:
        {
            time_t t = condition;
            struct tm *tm_now = localtime(&t);
            int year = tm_now->tm_year;
            int mon = tm_now->tm_mon;
            int day = tm_now->tm_mday;
            SYS_LOG *q = in->next;
            while(q)
            {
                t = q->time;
                tm_now = localtime(&t);
                if(year == tm_now->tm_year && mon == tm_now->tm_mon && day == tm_now->tm_mday)
                {
                    SYS_LOG *tmp = malloc(sizeof(SYS_LOG));
                    memcpy(tmp, q, sizeof(SYS_LOG));
                    *next = tmp;
                    tmp->next = 0;
                    next = &tmp->next;
                    ++ret;
                }
                q = q->next;
            }
        }
        break;
    case LOG_TYPE_SAME_CODE:
        {
            SYS_LOG *q = in->next;
            while(q)
            {
                if(q->code == condition)
                {
                    SYS_LOG *tmp = malloc(sizeof(SYS_LOG));
                    memcpy(tmp, q, sizeof(SYS_LOG));
                    *next = tmp;
                    tmp->next = 0;
                    next = &tmp->next;
                    ++ret;
                }
                q = q->next;
            }
        }
        break;
    default:
        {
            SYS_LOG *q = in->next;
            while (q)
            {
                SYS_LOG *tmp = malloc(sizeof(SYS_LOG));
                memcpy(tmp, q, sizeof(SYS_LOG));
                *next = tmp;
                tmp->next = 0;
                next = &tmp->next;
                ++ret;
                q = q->next;
            }
        }
        break;
    }
    out->total = ret;
    return ret;
}
/*
 *
 */
void SafeFreeLogList(SYS_LOG *list)
{
    while(list->next)
    {
        SYS_LOG *q = list->next;
        list->next = q->next;
        free(q);
    }
}

int GetLogTotalNum(MH_KNIT *p)
{
    return p->log_list.total;
}

/******************************************************************
 * below for payment
 ******************************************************************/
/*
 *
 */
void Decode(char *des, char *src, int len, int type)
{
    char key[8] = {'1', '5', '3', '3', '8', '6', '8', '9'};
    int i = 0;
    int page = len / 16;

    if ((src == NULL) || (des == NULL))
    {
        return;
    }

    for (i = 0; i < page; i++)
    {
        if (!Des_Go (des + i * 16, src + i * 16, key, type))
        {
            return;
        }
        if (!Des_Go (des + i * 16 + 8, src + i * 16 + 8, key, type))
        {
            return;
        }
    }
}
/*
 *
 */
static ushort DecodeCheckSum(ushort *data, ushort size)
{
    long sum = 0;

    while(size)
    {
        sum += *data++;
        size -= sizeof(unsigned short);
    }

    while(sum >> 16)
    {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }

    sum = ~sum & 0xFFFF;
    if (!sum)
    {
        sum = 0xFFFF;
    }

    return (ushort)sum;
}
/* \brief: check format of data
 *
 * \param: [in]data
 *       : [in]len-数据长度
 * \ret:   int - error code
 * \date:  2015.02.07
 * \author: wzwz
 */
int CheckPayment(uchar *data, int len)
{
    int ret = 0;
    ushort cs = DecodeCheckSum((ushort*)data, len);
    BOARD_CONFIG *cfg = (BOARD_CONFIG*)data;
    if((cfg->signature != ('M' | ('H' << 8))) || (cs != 0xFFFF))
    {
        ret = -1;
    }
    return ret;
}
/*
 *
 */
int InitPayment(MH_KNIT *p)
{
    int ret = 0;
    memset (&p->payment, 0, sizeof (BOARD_CONFIG));
    uchar des[sizeof(BOARD_CONFIG)] = {0};
    if(p->communication == COMM_SRAM)
    {
        uchar recv[2 + sizeof(BOARD_CONFIG)] = { 0 };
        ret = SramGetPayment(p->pmac, recv, sizeof(recv));
        if(!ret)
        {
            Decode((char*)des, (char*)&recv[2], sizeof(BOARD_CONFIG), DECRYPT);
            ret = CheckPayment(des, sizeof(BOARD_CONFIG));
        }
    }
    if(ret)
    {
        p->sys_info.lock = TRUE;
        p->knit_state.lock_read_error = TRUE;
    }
    else
    {
        memcpy(&p->payment, des, sizeof(BOARD_CONFIG));
    }
    return ret;
}
/*
 *
 */
int SavePayment(MH_KNIT *p)
{
    int ret = 0;
    uchar des[sizeof (BOARD_CONFIG)] = { 0 };
    BOARD_CONFIG cfg;
    static int lastsav = 0;

    cfg = p->payment;
    //checksum
    cfg.chksum = 0;
    cfg.signature = ('H' << 8) | 'M';
    cfg.last_time = time(NULL);
    cfg.chksum = DecodeCheckSum ((ushort*)&cfg, sizeof (BOARD_CONFIG));
    if (cfg.last_time - lastsav < 5)
    {
        return -6;
    }
    lastsav = cfg.last_time;

    //encrypt
    Decode((char*)des, (char*)&cfg, sizeof (BOARD_CONFIG), ENCRYPT);


    uchar data[6 + sizeof(BOARD_CONFIG)];
    memcpy (&data[6], des, sizeof (BOARD_CONFIG));
    if(p->communication == COMM_SRAM)
    {
        ret = SramSetPayment(p->pmac, data, sizeof(data));
    }

    return ret;
}
/*
 *
 */
int GetPaymentID(MH_KNIT *p, SYS_ID *pid)
{
    char out[16] = { 0 };
    char key[8] = {'1', '5', '3', '3', '8', '6', '8', '9'};
    char in[16] = { 0 };
    //company, times, days
    char id[8] = { 0 };

    memset(pid, 0, sizeof(SYS_ID));
    memcpy(in, p->payment.unid, sizeof(p->payment.unid));

    //获取硬件ID密钥
    if(!Des_Go(out, in, key, ENCRYPT))
    {
        return -1;
    }
    //获取公司信息
    if (!Des_Go (id, (char*)&(p->payment.id), key, ENCRYPT))
    {
        return -1;
    }

    in[0] = out[0];
    in[1] = out[1];
    in[2] = id[0];
    in[3] = id[1];
    memcpy(&in[4], &out[2], 5);
    memcpy(&in[9], &id[2], 6);
    in[15] = out[7];

    char key2[8] = {'2', '6', '9', '7', '6', '3', '3', '3'};

    if(!Des_Go(out, in, key2, ENCRYPT))
    {
        return -1;
    }

    if(!Des_Go(&out[8], &in[8], key2, ENCRYPT))
    {
        return -1;
    }

    memcpy(pid->id, out, sizeof(pid->id));
    pid->time_left = p->payment.set_time - p->payment.acc_time;

    return 0;
}
/*
 *
 */
int SetPaymentID(MH_KNIT *p, const char *sc, int size)
{
    char tmp[32] = {0};
    int i = 0;
    int j = 0;
    /*do not set if reading error for all info of payment is 0*/
    if(p->knit_state.lock_read_error)
    {
        return -5;
    }
    //delete space
    while(i < size)
    {
        if(!sc[i])
        {
            break;
        }
        if(sc[i] != ' ')
        {
            tmp[j] = sc[i];
            ++j;
        }
    }
    char code[16] = {0};
    for(i = 0, j = 0; j < 16; i += 2, ++j)
    {
        uchar h = 0;
        uchar l = 0;
        if(tmp[i] >= '0' && tmp[i] <= '9')
        {
            h = tmp[i] - '0';
        }
        else
        {
            h = h - 'A' + 10;
        }
        if(l >= '0' && l <= '9')
        {
            l = tmp[i + 1] - '0';
        }
        else
        {
            l = tmp[i + 1] - 'A' + 10;
        }
        code[j] = h * 16 + l;
    }
    char key[8] = {'1', '5', '3', '3', '8', '6', '8', '9'};
    char key2[8] = {'2', '6', '9', '7', '6', '3', '3', '3'};
    char out[16] = {0};
    ID *id;
    //第一次解密
    if(!Des_Go(out, code, key2, DECRYPT))
    {
        return -4;
    }

    if(!Des_Go(&out[8], &code[8], key2, DECRYPT))
    {
        return -4;
    }

    code[0] = out[0];
    code[1] = out[1];
    code[8] = out[2];
    code[9] = out[3];
    memcpy(&code[2], &out[4], 5);
    memcpy(&code[10], &out[9], 6);
    code[7] = out[15];
    //第2次解密
    if(!Des_Go((char*) out, (char*) &code, key, DECRYPT))
    {
        return -4;
    }

    if(!Des_Go((char*) &out[8], (char*) &code[8], key, DECRYPT))
    {
        return -4;
    }

    id = (ID*)&out[8];

    short times_o, times_n;

    times_o = (p->payment.id.times_h << 6) | p->payment.id.times;
    times_n = (id->times_h << 6) | id->times;
    //compare times and company
    if((times_o + 1 != times_n) || (p->payment.id.comp != id->comp))
    {
        return -2;
    }

    //compare ID
    if(memcmp(out, p->payment.unid, sizeof(p->payment.unid)))
    {
        return -3;
    }

    time_t tm = time(NULL);

    p->payment.signature = 'M' | ('H' << 8);
    p->payment.version = 0x10;
    p->payment.acc_time = 0;
    p->payment.set_time = id->days * 24 * 3600;

    p->payment.total_time = 0;

    p->payment.last_time = tm;

    p->payment.id = *id;

    p->payment.give = 0;

    return SavePayment(p);
}
/*
 *
 */
void LockPayment(MH_KNIT *p)
{
    p->sys_info.lock = TRUE;
}
/*
 *
 */
#define M18_TIME    46656000
void UpdatePayment(MH_KNIT *p, uint current)
{
    uint count = current - p->payment.last_time;
    p->payment.last_time = current;
    //total time
    if (p->payment.total_time < M18_TIME)
    {
        p->payment.total_time += count;
    }
    else
    {
        p->sys_info.lock = TRUE;
    }
    //setting time
    if (p->payment.acc_time < p->payment.set_time)
    {
        p->payment.acc_time += count;
    }
    else
    {
        p->sys_info.lock = TRUE;
    }
}
/*******************************************************************
 * payment end
 *******************************************************************/

/*******************************************************************
 *
 *******************************************************************/
int PowerOff(MH_KNIT *p)
{
    int ret = 0;
    SavePayment(p);
    if(p->communication == COMM_SRAM)
    {
        uchar recv[128 + 128] = {0, 0, 0, 0};
        ret = SramGetPowerOff(p->pmac, recv, 128);
        if(!ret)
        {
            ret = SramGetPowerOffExtra(p->pmac, &recv[128], 128);
        }
        if(!ret)
        {
            p->rock_pos = recv[128 + 37] & 0xFF;
            p->rock_pos <<= 8;
            p->rock_pos |= recv[128 + 36] & 0xFF;
            memcpy(&recv[128], &recv[128 + 42], 28);
            ret = WriteRawFile(CARRIAGE_PARAM_FILE, (void*)&recv[4], 124 + 28);
            if(!ret)
            {
                ret = WriteKnitFile(KNIT_PARAM_FILE, (void*)p);
            }
        }
    }
    else
    {
        ret = WriteKnitFile(KNIT_PARAM_FILE, (void*)p);
    }
    return ret;
}
/*
 *
 */
void InitKnitData(MH_KNIT *p)
{
    if(GetBackPieceValid(p))
    {
        p->backpiece_start_line = backpiece_get_start_row(p);
    }
    else
    {
        p->knit_state.fp_enable = FALSE;
        p->knit_state.bp_enable = FALSE;
    }
    if(GetWhichNeedDo(p) == NEED_DO_GOON_KNIT)
    {
        if(p->knit_state.prefix)
        {
            p->need_loop = 0;
        }
        else
        {
            p->need_loop = 0x01;
        }
        p->need_loop_record = 0;

        pk_clear_data(p);

        if(p->board_enable)
        {
            pk_init_data(p, 1, 0, FALSE);
        }
    }
}
/*
 *
 */
int RestoreKnitAfterPowerOn(MH_KNIT *p)
{
    int ret = 0;
    if(p->knit_state.bp_enable)
    {
        p->hangding_start = p->backpiece_start_line - 1 + p->hd_start_base;
        p->hangding_end = p->backpiece_start_line - 1 + p->hd_end_base;
    }
    else
    {
        p->hangding_start = p->hd_start_base;
        p->hangding_end = p->hd_end_base;
    }
    p->knit_state.goon = TRUE;
    if(p->communication == COMM_SRAM)
    {
        int prefix = p->knit_state.prefix;
        int aux_index = p->aux_list.index;
        ushort send_line = p->curt_line + 1;
        if(aux_index > -1 && aux_index < p->aux_list.num)
        {
            send_line = p->aux_list.line + 1;
        }
        GetNormalKnitData(p, p->sram_send_data, send_line, prefix, aux_index);
        p->sram_send_data[2] = send_line;
        p->sram_send_data[3] = send_line >> 8;
        if(SramSendContinueData(p->pmac, p->sram_send_data, sizeof(p->sram_send_data)))
        {
            return -1;
        }
        char data[SEND_MAX_SIZE] = {0};
        memcpy(data, p->sram_send_data, sizeof(data));
        ushort next_line = GetNextLine(p, send_line, &prefix, &aux_index);
        GetNormalKnitData(p, p->sram_send_data, next_line, prefix, aux_index);
        memcpy(&p->sram_send_data[ARM2DSP_CHANGABLE_BYTE2], &data[ARM2DSP_CHANGABLE_BYTE2], ARM2DSP_CHANGABLE_SIZE2);
        memcpy(&p->sram_send_data[ARM2DSP_CHANGABLE_BYTE1], &data[ARM2DSP_CHANGABLE_BYTE1], ARM2DSP_CHNAGABLE_SIZE1);
        memcpy(&p->sram_send_data[ARM2DSP_CHANGABLE_BYTE3], &data[ARM2DSP_CHANGABLE_BYTE3], ARM2DSP_CHNAGABLE_SIZE3);
        p->sram_send_data[2] = send_line;
        p->sram_send_data[3] = send_line >> 8;
        if(SramRetrySendKnitData(p->pmac, p->sram_send_data, sizeof(p->sram_send_data), 10))
        {
            return -1;
        }
        next_line = GetNextLine(p, next_line, &prefix, &aux_index);
        GetNormalKnitData(p, p->sram_send_data, next_line, prefix, aux_index);
        p->sram_send_data[2] = send_line;
        p->sram_send_data[3] = send_line >> 8;
        p->param_change = TRUE;
        usleep(10000);
        p->knit_state.drt = !((send_line - 1) & 1);
    }
    return ret;
}
/*
 *
 */
int GetHighRollerFrequency(MH_KNIT *p, int speed)
{
    int ret = 0;
    ushort min = 10;
    ushort max = 200;
    if(p->company == COMPANY_HQ)
    {
        min = p->rab_min_param;
        max = p->rab_max_param;
    }
    if(speed)
    {
        float f = 10 + (max - min)/99.0 * (speed - 1);
        ret = 1000 / f;
    }
    return ret;
}
/*
 * return needle
 */
int GetYarnNeedleBetweenCam(MH_KNIT *p)
{
    return p->yarn_inter_4cam * p->inch_type / MM_PER_INCH;
}
/*
 * get mm
 */
ushort GetYarnDistanceOfCam(MH_KNIT *p)
{
    p->yarn_inter_4cam = 158;
    return p->yarn_inter_4cam;
}
/*
 * set mm
 */
void SetYarnDistanceOfCam(MH_KNIT *p, ushort dist)
{
    p->yarn_inter_4cam = dist;
}
/*
 *
 */
void SwitchScreenSaver(MH_KNIT *p, int on)
{
    int tm = 0;
    if(p->company == COMPANY_HQ)
    {
        if(p->save_screen_enable)
        {
            tm = p->save_screen_time;
        }
    }
    else
    {
        tm = p->save_screen_time;
    }
    if(tm)
    {
        if(on)
        {
//            Ts485SetScreenSaver(tm * 60);
        }
        else
        {
//            Ts485SetScreenSaver(0);
        }
    }
}
/*
 *
 */
uchar GetDriverType(MH_KNIT *p)
{
    return p->mac.driver_type;
}
/*
 *
 */
void SetDriverType(MH_KNIT *p, uchar type)
{
    p->mac.driver_type = type;
}
